package org.vacoor.xqq.ui;

import com.google.common.eventbus.Subscribe;
import org.vacoor.nothing.ui.hotkey.OSHotKeyEvent;
import org.vacoor.nothing.ui.hotkey.OSHotKeyListener;
import org.vacoor.nothing.ui.hotkey.OSHotKeyManager;
import org.vacoor.nothing.ui.trayicon.AppSysTrayIcon;
import org.vacoor.nothing.ui.trayicon.TrayAnimatedIcon;
import org.vacoor.xqq.Login3;
import org.vacoor.xqq.core.bean.Buddy;
import org.vacoor.xqq.core.bean.Discussion;
import org.vacoor.xqq.core.bean.Group;
import org.vacoor.xqq.core.bean.Peer;
import org.vacoor.xqq.core.poll.impl.AbstractPollReply;
import org.vacoor.xqq.core.poll.impl.BuddyReply;
import org.vacoor.xqq.core.poll.impl.DiscuReply;
import org.vacoor.xqq.core.poll.impl.GroupReply;
import org.vacoor.xqq.ui.comp.tree.AnimatedTree;
import org.vacoor.xqq.ui.comp.tree.IdentifiableAndObservableDataNode;
import org.vacoor.xqq.ui.comp.tree.PeerListener;
import org.vacoor.xqq.ui.comp.tree.PeerNode;
import org.vacoor.xqq.ui.i.Chat2;
import org.vacoor.xqq.ui.i.ChatManager2;

import javax.swing.*;
import java.awt.*;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 消息派发器
 *
 * @author: Vacoor
 */
public class MessageDispatcher {
    private final Object lock = new Object();
    private ConcurrentHashMap<Long, Vector<AbstractPollReply>> msgStack = new ConcurrentHashMap<Long, Vector<AbstractPollReply>>();
    private Peer peer;
    private ChatManager2 chatManager;
    private AnimatedTree buddiesTree;
    private AnimatedTree discusTree;
    private AnimatedTree groupsTree;

    public MessageDispatcher(ChatManager2 chatManager, AnimatedTree buddiesTree, AnimatedTree discusTree, AnimatedTree groupsTree) {
        this.chatManager = chatManager;
        this.buddiesTree = buddiesTree;
        this.discusTree = discusTree;
        this.groupsTree = groupsTree;
        init();
    }

    public void init() {
        new PeerListener() {
            @Override
            public void mouseClickedOnBuddy(Buddy buddy) {
                openChat(buddy);
                peer = null;
            }
        }.bind(buddiesTree);

        new PeerListener() {
            @Override
            protected void mouseClickedOnDiscussion(Discussion discu) {
                openChat(discu);
                peer = null;
            }
        }.bind(discusTree);

        new PeerListener() {
            @Override
            protected void mouseClickedOnGroup(Group group) {
                openChat(group);
                peer = null;
            }
        }.bind(groupsTree);

        //
        OSHotKeyManager hotKeyManager = OSHotKeyManager.getCurrentOSHotKeyManager();
        if (hotKeyManager == null) {
            return;
        }
        hotKeyManager.getOSHotKeyBinder(Login3.OS_SHOW_IDENTIFER).addOSHotKeyListener(new OSHotKeyListener() {
            @Override
            public void onOSHotKey(OSHotKeyEvent event) {
                if (peer != null) {
                    openChat(peer);
                    peer = null;
                    return;
                }
                Window window = SwingUtilities.windowForComponent(buddiesTree);
                if (window == null) {
                    return;
                }
                if (window instanceof Frame) {
                    Frame f = (Frame) window;
                    f.setVisible(!f.isActive());
                } else {
                    window.setVisible(!window.isVisible());
                }
            }
        });
    }

    @Subscribe
    public void onMsg(AbstractPollReply msg) {
        long cid = msg.getFromUin();    // 这里处理过, 不应该会出错
        IdentifiableAndObservableDataNode node = null;
        if (msg instanceof BuddyReply) {
            node = buddiesTree.getIdentifiableAndObservableNode(cid);
        } else if (msg instanceof DiscuReply) {
            node = discusTree.getIdentifiableAndObservableNode(((DiscuReply) msg).getDid());
        } else if (msg instanceof GroupReply) {
            node = groupsTree.getIdentifiableAndObservableNode(((GroupReply) msg).getGroupCode());  // todo 这里比较坑
        }
        if (node == null || !(node instanceof PeerNode)) {
            return;
        }
        Peer peer = ((PeerNode) node).getData();
        Chat2 chat = chatManager.getChat(peer, false);

        // 如果不在聊天列表中, 将压入消息栈, 并唤醒用户
        if (chat == null) {
            pushMsg(msg);
            this.peer = peer;
            if (peer instanceof Buddy) {
                buddiesTree.setShaking(peer.getId(), true);
            } else if (peer instanceof Discussion) {
                discusTree.setShaking(peer.getId(), true);
            } else if (peer instanceof Group) {
                groupsTree.setShaking(((Group) peer).getCode(), true);
            }
            TrayAnimatedIcon trayIcon = AppSysTrayIcon.getCurrentAppTrayAnimatedIcon();
            Icon avatar = peer.getAvatar();
            if (trayIcon != null && avatar != null) {
                trayIcon.addFlashAnimation(peer.getId(), ((ImageIcon) avatar).getImage(), false);
            }
        } else {    // 直接写入消息
            chat.writeMessage(msg);
            chatManager.notifyUser(chat);
            this.peer = null;
        }
    }

    /**
     * 打开与给定联系人的 Chat, 如果需要则创建新 Chat
     */
    public synchronized void openChat(Peer peer) {
        Chat2 chat = chatManager.getChat(peer, true);
        Vector<AbstractPollReply> buddyMessages = pickUpMsg(peer instanceof Group ? ((Group) peer).getCode() : peer.getId());
        for (AbstractPollReply m : buddyMessages) {
            chat.writeMessage(m);
        }
        chatManager.setCurrentChat(chat);
        if (peer instanceof Buddy) {
            buddiesTree.setShaking(peer.getId(), false);
        } else if (peer instanceof Discussion) {
            discusTree.setShaking(peer.getId(), false);
        } else if (peer instanceof Group) {
            groupsTree.setShaking(((Group) peer).getCode(), false);
        }
        TrayAnimatedIcon trayIcon = AppSysTrayIcon.getCurrentAppTrayAnimatedIcon();
        if (trayIcon != null) {
            trayIcon.removeAnimation(peer.getId());
        }
    }

    public Vector<AbstractPollReply> pickUpMsg(long cid) {
        Vector<AbstractPollReply> buddyMessages = msgStack.remove(cid);
        if (buddyMessages == null) {
            buddyMessages = new Vector<AbstractPollReply>();
        }
        return buddyMessages;
    }

    protected void pushMsg(AbstractPollReply msg) {
        final long fid = msg instanceof BuddyReply ? msg.getFromUin() : (msg instanceof DiscuReply ? ((DiscuReply) msg).getDid() : (msg instanceof GroupReply ? ((GroupReply) msg).getGroupCode() : -1));
        Vector<AbstractPollReply> fmsg = msgStack.get(fid);
        synchronized (lock) {
            if (null == msgStack.get(fid)) {
                fmsg = new Vector<AbstractPollReply>();
                msgStack.put(fid, fmsg);
            }
        }
        fmsg.add(msg);
    }
}
